﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Us.Mil.Osd.Acq.Damir.Tamarin;
using Us.Mil.Osd.Acq.Damir.Orca;
using Us.Mil.Osd.Acq.Damir.Mongoose;
using System.Data.SqlClient;
using ViewModel.DataAccessLayer;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
using System.Runtime.Serialization;
using System.Diagnostics;

namespace BusinessObjectsT4
{
	public class Tests
	{
		static string connectionstring = "server=.;database=damirdev;integrated security=true;";



		public static void TryConvertToDamirLite()
		{
						
			//attemptToSerialize<SecureDecimal>(new SecureDecimal(4.2m));
			Debug.Listeners.Add(new TextWriterTraceListener(@"E:\caci\Orca\BusinessObjectsT4\convert-class-output.txt"));
			Debug.AutoFlush = true;

			Type srcType = typeof(PerformanceDataPoint);
			Type destType = typeof(DamirLite.Tamarin.PerformanceDataPoint);
			writeConvertType(destType, srcType);

			DataAccess data = new SqlDataAccess(connectionstring);
			var DamirLitelist = new List<List<DamirLite.Tamarin.PerformanceDataPoint>>();
			var damirList = data.Get<PerformanceDataPoint>();			
						
			foreach (var srcDataPoint in damirList)
			{
				var destDataPoint = convert2(srcDataPoint);
			}
		}

		static DamirLite.Tamarin.PerformanceDataPoint convert2(PerformanceDataPoint src1)
		{
			dynamic dest0, src0;//so that property names can be reused
			var dest1 = new DamirLite.Tamarin.PerformanceDataPoint();
			dest1.Program = src1.Program;
			dest1.EstimateType = src1.EstimateType;
			dest1.EffectiveDate = src1.EffectiveDate;
			dest1.Subprograms = new DamirLite.Tamarin.PerformanceSubprogramCollection();
			foreach (var src2 in src1.Subprograms)
			{
				var dest2 = new DamirLite.Tamarin.PerformanceSubprogram();
				dest2.URI = src2.URI;
				dest2.HasSIPRNETBreaches = src2.HasSIPRNETBreaches;
				dest2.Sections = new DamirLite.Tamarin.PerformanceSectionCollection();
				foreach (var src3 in src2.Sections)
				{
					var dest3 = new DamirLite.Tamarin.PerformanceSection();
					dest3.Origin = src3.Origin;

					//Type not equal: IEnumerable
					dest3.Characteristics = new DamirLite.Tamarin.PerformanceCharacteristicCollection();//instantiate a DamirLite copy
					foreach (var src4 in src3.Characteristics)
					{
						//dynamic dest4?
						var dest4 = new DamirLite.Tamarin.PerformanceCharacteristic();//instantiate a DamirLite copy
						dest4.URI = src4.URI;
						dest4.Header = src4.Header;
						dest4.Name = src4.Name;
						dest4.CriticalTechnologyName = src4.CriticalTechnologyName;

						

						//Estimate: Type not equal
						src0 = src4.Estimate;
							dest0 = new DamirLite.Tamarin.CharacteristicValue();//instantiate a DamirLite copy
							dest0.Placeholder = src0.Placeholder;
							dest0.Value = src0.Value;
							//what if property Type not equal here?
								//srcX = new src0.SomeProperty
								//destX = new DamirLite.Tamarin.SomePropertyClass()

						dest4.Estimate = dest0;//return; finally, set the new copy

						//Threshold: Type not equal
						src0 = src4.Threshold;
						src0 = new DamirLite.Tamarin.CharacteristicValue();
						dest0.Placeholder = src0.Placeholder;
						dest0.Value = src0.Value;
						dest4.Threshold = dest0;

						src0 = src4.Demonstrated;
						dest0 = new DamirLite.Tamarin.DemonstratedPerformance();
						src0 = src0.Measurement;
						dest0 = new DamirLite.Tamarin.CharacteristicValue();
						dest0.Placeholder = src0.Placeholder;
						dest0.Value = src0.Value;
						dest0.Measurement = dest0;


						//var dest4 = new DamirLite.Tamarin.PerformanceCharacteristic();
						//dest4.URI = src4.URI;
						//dest4.Header = src4.Header;
						//dest4.Name = src4.Name;
						//dest4.CriticalTechnologyName = src4.CriticalTechnologyName;						

						////if property type not equal (and not IEnumerable)
						//srcN = src4.Estimate;
						//destN = new DamirLite.Tamarin.CharacteristicValue();
						//destN.Placeholder = srcN.Placeholder;
						//destN.Value = srcN.Value;
						//dest4.Estimate = destN;//lastly, set the property (like Add( ) for IEnumerable)

						//srcN = src4.Threshold;
						//destN = new DamirLite.Tamarin.CharacteristicValue();
						//destN.Placeholder = srcN.Placeholder;
						//destN.Value = srcN.Value;
						//dest4.Threshold = destN;
						


					}
				}
			}
			return dest1;
		}


		static void writeConvertType2(Type destType, Type srcType, int lvl = 1)
		{
			if (lvl == 1)
			{
				System.Diagnostics.Debug.WriteLine("dynamic destN, srcN;//so that property names can be reused");
			}
			if (lvl == N)//destN, srcN
			{
				System.Diagnostics.Debug.WriteLine("destN = new " + Program.GenericTypeFullNameToString(destType) + "();");
			}
			else
				System.Diagnostics.Debug.WriteLine("var dest{0} = new {1}();", lvl, Program.GenericTypeFullNameToString(destType));

			var commonProperties = from destP in destType.GetProperties()
								   join srcP in srcType.GetProperties()
										on destP.Name equals srcP.Name
								   select new { desttype = destP.PropertyType, srctype = srcP.PropertyType, Name = srcP.Name };
			foreach (var common in commonProperties)
			{
				Type srcElementType;
				if (common.desttype == common.srctype)//base case: would-be return;
					System.Diagnostics.Debug.WriteLine("dest{0}.{1} = src{2}.{3};", lvl, common.Name, lvl, common.Name);
				else if (Program.isGenericEnumerableType(common.srctype, out srcElementType))
				{
					Type destElementType = (from dtype in Program.destAssembly.GetTypes()
											where dtype.Name == srcElementType.Name
											//&& dtype.Namespace == destType.Namespace
											select dtype).First();

					System.Diagnostics.Debug.WriteLine("dest{0}.{1} = new {2}();"
						, lvl
						, common.Name
						, Program.GenericTypeFullNameToString(common.desttype));
					System.Diagnostics.Debug.WriteLine("foreach (var src{0} in src{1}.{2}", lvl + 1, lvl, common.Name);
					System.Diagnostics.Debug.WriteLine("{");
					//System.Diagnostics.Debug.WriteLine("var dest{0} = new {1}()", lvl + 1, destElementType.FullName);						
					writeConvertType(destElementType, srcElementType, lvl + 1);
					System.Diagnostics.Debug.WriteLine("}");
					System.Diagnostics.Debug.WriteLine("dest{0}.{1}.Add(dest{2});", lvl, common.Name, lvl + 1);
				}
				else//if property type not equal (and not IEnumerable)
				{
					System.Diagnostics.Debug.WriteLine("srcN = src{0}.{1};", lvl, common.Name);//if property type not equal (and not IEnumerable)
					writeConvertType(common.desttype, common.srctype, N);
					System.Diagnostics.Debug.WriteLine("dest{0}.{1} = destN;", lvl, common.Name);
				}

			}
		}

		const int N = 0;
		//3 cases (1) IEnumerable (2) property Type equal (3) two different class types
		//use dynamic keyword? but the Type is known at generation (compile) time.
		static void writeConvertType(Type destType, Type srcType, int lvl = 1)
		{
			if (lvl == 1)
			{
				System.Diagnostics.Debug.WriteLine("dynamic destN, srcN;//so that property names can be reused");
			}
			if (lvl == N)//destN, srcN
			{
				System.Diagnostics.Debug.WriteLine("destN = new " + Program.GenericTypeFullNameToString(destType) + "();");
			}
			else
				System.Diagnostics.Debug.WriteLine("var dest{0} = new {1}();", lvl, Program.GenericTypeFullNameToString(destType));

			var commonProperties = from destP in destType.GetProperties()
								   join srcP in srcType.GetProperties()
										on destP.Name equals srcP.Name
								   select new { desttype = destP.PropertyType, srctype = srcP.PropertyType, Name = srcP.Name };
			foreach (var common in commonProperties)
			{
				Type srcElementType;
				if (common.desttype == common.srctype)//base case: would-be return;
					System.Diagnostics.Debug.WriteLine("dest{0}.{1} = src{2}.{3};", lvl, common.Name, lvl, common.Name);
				else if (Program.isGenericEnumerableType(common.srctype, out srcElementType))
				{
					Type destElementType = (from dtype in Program.destAssembly.GetTypes()
											where dtype.Name == srcElementType.Name
											//&& dtype.Namespace == destType.Namespace
											select dtype).First();

					System.Diagnostics.Debug.WriteLine("dest{0}.{1} = new {2}();"
						, lvl
						, common.Name
						, Program.GenericTypeFullNameToString(common.desttype));
					System.Diagnostics.Debug.WriteLine("foreach (var src{0} in src{1}.{2}", lvl + 1, lvl, common.Name);
					System.Diagnostics.Debug.WriteLine("{");
					//System.Diagnostics.Debug.WriteLine("var dest{0} = new {1}()", lvl + 1, destElementType.FullName);						
					writeConvertType(destElementType, srcElementType, lvl + 1);
					System.Diagnostics.Debug.WriteLine("}");
					System.Diagnostics.Debug.WriteLine("dest{0}.{1}.Add(dest{2});", lvl, common.Name, lvl + 1);
				}
				else//if property type not equal (and not IEnumerable)
				{
					System.Diagnostics.Debug.WriteLine("srcN = src{0}.{1};", lvl, common.Name);//if property type not equal (and not IEnumerable)
					writeConvertType(common.desttype, common.srctype, N);
					System.Diagnostics.Debug.WriteLine("dest{0}.{1} = destN;", lvl, common.Name);
				}
					
			}
		}
		
		static void setProperties(Type destType, Type srcType, string name)
		{
			//if (destType == srcType)
			//{
			//    Console.WriteLine("{0} = {1}", destName, srcName);
			//    return;
			//}

			var commonProperties = from destP in destType.GetProperties()								   
								   join srcP in srcType.GetProperties() 
										on destP.Name equals srcP.Name
								   select new { desttype= destP.PropertyType, srctype = srcP.PropertyType, Name = srcP.Name };
			foreach (var common in commonProperties)
			{
				if (common.desttype == common.srctype)//base case: would-be return;
					Console.WriteLine("{0}.{1} = {2}.{3}", destType.Name, common.Name, srcType, common.Name);
				else
					setProperties(common.desttype, common.srctype, common.Name);
			}

			return;
		}

		static void attemptToSerialize<T>(T objects)
		{
			DataContractSerializer serializer = new DataContractSerializer(typeof(T));
			byte[] buffer;
			using (MemoryStream memstream = new MemoryStream())
			{
				serializer.WriteObject(memstream, objects);
				memstream.Position = 0;
				serializer.ReadObject(memstream);
				buffer = memstream.GetBuffer();				
			}

			
		}
		public static void checkHelperMethods()
		{
			string prefix;
			prefix = Program.GetClassPrefix(typeof(PerformanceDataPointKey));
			prefix = Program.GetClassPrefix(typeof(SubmissionHistoryActionEnum));
			prefix = Program.GetClassPrefix(typeof(SecureDecimal));
			prefix = Program.GetClassPrefix(typeof(SecurityDescriptor));
		}
		static void genericsToStrings()
		{
			string s;
			//Type many = typeof(Tuple<List<string>, Nullable<DateTime>>);
			//Type nested = typeof(IEnumerable<Nullable<int>>);
			//s = GenericTypeFullNameToString(nested);			

			//Type desercontext = typeof(Us.Mil.Osd.Acq.Damir.Orca.Serialization.DeserializationContext<>);
			//s = GenericTypeFullNameToString(desercontext);

			//Type interfType = typeof(IList<Us.Mil.Osd.Acq.Damir.Tamarin.IKeyedDataPoint>);
			//s = GenericTypeFullNameToString(interfType);	

			//Type collection = typeof(Us.Mil.Osd.Acq.Damir.Tamarin.SecureCollection<string>)
			//bool isEnumerable;
			//bool isg;
			//Type collection = typeof(Us.Mil.Osd.Acq.Damir.Tamarin.LargeActiveContractCollection);
			//s = getClassInheritanceSuffix(collection);

			//Type b = BasemostType(collection);
			//collection = b;
			//isEnumerable = collection.GetInterfaces().Contains(typeof(System.Collections.IEnumerable));
			//s = getClassInheritanceSuffix(collection);

			//collection = typeof(Us.Mil.Osd.Acq.Damir.Tamarin.SecureCollection<>);
			//s = getClassInheritanceSuffix(collection);
			//s = GenericTypeFullNameToString(collection);

			//collection = typeof(Us.Mil.Osd.Acq.Damir.Orca.SecurityTokenCollection);
			//s = getClassInheritanceSuffix(collection);

			//Type secure = _businessObjects.GetTypes().First(t => t.Name.Contains("SecureEnum"));
			//s = GenericTypeFullNameToString(secure);
			//s = GenericTypeNameToString(secure);

		}

		//int x = 1, y = 2;
		//set<int>(ref x, ref y);		//this does swap x, y
		//Tuple<int, string> t1 = new Tuple<int, string>(1, "one");
		//Tuple<int, string> t2 = new Tuple<int, string>(2, "two");
		//set<string>(ref t1.Item2 ,ref t2.Item2);	//properties won't work
		//static void set<T>(ref T a, ref T b)
		//{
		//    a = b;
		//}
	}
}
